package com.altekis.kanbankaze.client;

import com.altekis.kanbankaze.shared.UserAccount;
import com.altekis.kanbankaze.shared.events.LoginCompleteEvent;
import com.altekis.kanbankaze.shared.events.LoginCompleteEventHandler;
import com.altekis.kanbankaze.shared.messages.Message;
import com.altekis.kanbankaze.shared.messages.TrojanMessage;
import com.google.gwt.appengine.channel.client.Channel;
import com.google.gwt.appengine.channel.client.ChannelFactory;
import com.google.gwt.appengine.channel.client.ChannelFactory.ChannelCreatedCallback;
import com.google.gwt.appengine.channel.client.SocketError;
import com.google.gwt.appengine.channel.client.SocketListener;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamFactory;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.ui.RootPanel;
/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Kanbankaze implements EntryPoint {

	protected TaskServiceAsync taskService = Injector.INSTANCE.getTaskServiceAsync();

	// Logged user
	public static UserAccount loggedUser = null;

	// Factory for processing of push messages
	SerializationStreamFactory pushServiceStreamFactory;


	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		RootPanel rootPanel = RootPanel.get("kanbanContainer");

		pushServiceStreamFactory =(SerializationStreamFactory) TaskService.App.getInstance();

		// Attach events

		// Add Event Bus handlers - LOGIN COMPLETED
		final Injector injector = Injector.INSTANCE;
		injector.getEventBus().addHandler(LoginCompleteEvent.TYPE, new LoginCompleteEventHandler()     {
			@Override
			public void onLoginComplete(LoginCompleteEvent loginCompleteEvent) {
				createChannel(loginCompleteEvent.userAccount);
			}
		});

		// Generate & show a new Kanban Presenter + View
		KanbanPresenter kanbanPresenter = injector.getKanbanPresenter();
		KanbanView kanbanView = new KanbanView();
		kanbanView.getElement().setId("kanbanView");
		kanbanView.getElement().getStyle().setPosition(Position.RELATIVE);
		kanbanPresenter.bindDisplay(kanbanView);
		kanbanPresenter.show();
		rootPanel.add(kanbanView);
	}

	public void createChannel(UserAccount user) {
		loggedUser = user;
		GWT.log("Creating channel for user : " + user.getLogin() + "[" + user.getChannelId()+ "]");
		// Open Channel
		ChannelFactory.createChannel(
				Kanbankaze.loggedUser.getChannelId(), 
				new ChannelCreatedCallback() {
					@Override
					public void onChannelCreated(Channel channel) {
						GWT.log("Created channel [" + channel.toString() + "]");
						channel.open(new SocketListener() {
							@Override
							public void onOpen() {
								GWT.log("Channel opened!"); // TODO Remove
							}
							@Override
							public void onMessage(String serializedMessage) {
								GWT.log("Mensaje recibido [" + serializedMessage + "]");
								doProcessMessage(serializedMessage);
							}
							@Override
							public void onError(SocketError error) {
								GWT.log("Error: " + error.getDescription()); // TODO Remove
							}
							@Override
							public void onClose() {
								GWT.log("Channel closed!"); // TODO Remove
							}
						});
					}
				});
	}

	// All push messages are distributed here
	private void doProcessMessage(String serializedMessage) {
		try {
			SerializationStreamReader reader = pushServiceStreamFactory.createStreamReader(serializedMessage);
			Message message = (Message) reader.readObject();
			// Message discrimination
			if (message.getClass().equals(TrojanMessage.class)) {
				// Trojan Message releases its trojan Event directly
				Injector.INSTANCE.getEventBus().fireEvent(((TrojanMessage)message).getEvent());
				/* ADD ALL MESSAGE-EVENT MAPPINGS HERE */
			} else {
				Window.alert("ERROR: Unable to map Message " + message.getClass().getName() + " to corresponding event");
			}
		} catch (SerializationException e) {
			Window.alert("Exception " + e.toString());
			throw new RuntimeException("Unable to deserialize " + serializedMessage, e);
		}
	}
}